package com.ev.scm.service.impl;

import com.alibaba.fastjson.JSON;
import com.ev.apis.model.DsResultResponse;
import com.ev.custom.domain.DictionaryDO;
import com.ev.custom.service.ContentAssocService;
import com.ev.custom.service.DictionaryService;
import com.ev.custom.service.MaterielService;
import com.ev.framework.config.Constant;
import com.ev.framework.config.ConstantForGYL;
import com.ev.framework.il8n.MessageSourceHandler;
import com.ev.framework.utils.*;
import com.ev.scm.dao.DeliveryNoteDao;
import com.ev.scm.dao.DeliveryNoteItemDao;
import com.ev.scm.domain.DeliveryNoteDO;
import com.ev.scm.domain.DeliveryNoteItemDO;
import com.ev.scm.domain.SalescontractItemDO;
import com.ev.scm.service.IDeliveryNoteService;
import com.ev.scm.service.SalescontractItemService;
import com.ev.scm.service.StockOutItemService;
import com.ev.scm.vo.CountBean;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Description 发货通知实现类
 * Company Xin Soft
 **/
@Service
public class DeliveryNoteServiceImpl implements IDeliveryNoteService {

    /** 消息处理 */
    @Resource
    private MessageSourceHandler messageSourceHandler;
    /** 发货通知主表mapper */
    @Resource
    private DeliveryNoteDao deliveryNoteDao;
    @Resource
    private DeliveryNoteItemDao deliveryNoteItemDao;
    /** 销售合同服务 */
    @Resource
    private SalescontractItemService salescontractItemService;
    /** 物料服务 */
    @Resource
    private MaterielService materielService;
    /** 字典服务 */
    @Resource
    private DictionaryService dictionaryService;
    /** 附件上传服务 */
    @Resource
    private ContentAssocService contentAssocService;
    /** 出库服务 */
    @Resource
    private StockOutItemService stockOutItemService;

    /** slf4j日志 */
    private static final Logger LOGGER = LoggerFactory.getLogger(DeliveryNoteServiceImpl.class);

    @Override
    public R saveHandle(DeliveryNoteDO deliveryNoteDO, String bodyItem, String uploadAttachment, Long[] itemIds) throws Exception {
        try {
            Map<String, Object> result = new HashMap<>(2);
            List<DeliveryNoteItemDO> itemDos;
            if (StringUtils.isNotBlank(bodyItem)) {
                itemDos = JSON.parseArray(bodyItem, DeliveryNoteItemDO.class);
            } else {
                return R.error(messageSourceHandler.getMessage("common.massge.dateIsNon", null));
            }
            // TODO 检验合同
            //检查合同发货数量，判断是否能保存 检查结果为null则通过，非null则返回报错
            R checkRes = checkSourceCounts(itemDos,deliveryNoteDO.getId());
            if (checkRes != null) {
                return checkRes;
            }
            boolean isInsert = deliveryNoteDO.getId() == null;
            // TODO 新增或更新主表
            //新增
            if (isInsert) {
                DictionaryDO storageType = dictionaryService.get(ConstantForGYL.FHTZ);
                //获取前12位编号
                String prefix = DateFormatUtil.getWorkOrderno(storageType.getValue());
                //获取最大单据编号
                String maxCode = deliveryNoteDao.findMaxCode(prefix);
                //生成单据编号
                String code = DateFormatUtil.getWorkOrderno(prefix, maxCode);
                deliveryNoteDO.setDeliveryCode(code);
                //默认待审核
                deliveryNoteDO.setAuditSign(Constant.WAIT_AUDIT);
            }
            int successCount = deliveryNoteDao.saveDeliveryNote(deliveryNoteDO);
            LOGGER.info("主表成功保存数量:{}",successCount);
            //返回id
            result.put("id",deliveryNoteDO.getId());
            // TODO 新增或更新子表
            //设主表id
            itemDos.forEach(item -> item.setMainId(deliveryNoteDO.getId()));
            deliveryNoteItemDao.saveBeans(itemDos);
            // TODO 上传附件
            contentAssocService.saveList(deliveryNoteDO.getId(),uploadAttachment, ConstantForGYL.DELIVERY_NOTE_FILE, isInsert);
            // TODO 批量刪除发货通知子表
            if (!isInsert && itemIds != null && itemIds.length > 0) {
                deliveryNoteItemDao.batchDelDeliveryNoteItem(Arrays.asList(itemIds));
            }
            return R.ok(result);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage(),e);
            throw e;
        }
    }

    /**
     * 检查是否有可用库存
     * @param builder 构造库存ids字符串
     * @param params 封装map数据后面校验使用 《库存id集合，发货数量》
     * @return 有或无
     */
    private boolean checkStockCount(StringBuilder builder,Map<String, BigDecimal> params) throws Exception{
        //分组查询可用库存
        List<Map<String, Object>> ableCountList = materielService.findAbleCount(builder.toString());
        if (CollectionUtils.isEmpty(ableCountList)) {
            //未查到库存
            return false;
        }
        Iterator<Map<String, Object>> iter = ableCountList.iterator();
        //循环判断数量是否超出
        while (iter.hasNext()) {
            Map<String, Object> map = iter.next();
            //分组库存id集合
            String stockIds = map.get("id").toString();
            if (params.containsKey(stockIds)) {
                //传参发货数量
                BigDecimal deliveryCount = MathUtils.getBigDecimalByZero(params.get(stockIds));
                //库存数量
                BigDecimal stockCount = MathUtils.getBigDecimalByZero(map.get(stockIds));
                if (stockCount.compareTo(deliveryCount) < 0) {
                    //库存不足
                    return false;
                }
            }
        }
        //库存充足
        return true;
    }

    @Override
    public List<CountBean>  findCountBySource(List<Object> sourceIds, Long sourceType) throws Exception {
        try {
            return deliveryNoteItemDao.findCountBySource(sourceIds,sourceType);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage(),e);
            throw e;
        }
    }

    /**
     * 检查合同发货数量，判断是否能保存
     * @param itemDos 子表数据
     * @param id 主表id
     */
    private R checkSourceCounts(List<DeliveryNoteItemDO> itemDos, Long id) throws Exception{

        //将入参子表数据 根据合同sourceId分组合并发货数量
        Map<Long, BigDecimal> inDeliveryCountMap = itemDos
                .stream()
                .filter(e -> e.getSourceId() != null)
                .collect(Collectors.toMap(DeliveryNoteItemDO::getSourceId, DeliveryNoteItemDO::getDeliveryCount, BigDecimal::add));

        //获取原先单据的发货数量
        Map<Long, BigDecimal> oldDeliveryCountMap = Maps.newHashMapWithExpectedSize(16);
        //更新触发
        if (id != null) {
            //根据主表id查询子表明细
            List<DeliveryNoteItemDO> list = deliveryNoteItemDao.findDetailByMainId(id);
            if (list.size() > 0) {
                oldDeliveryCountMap = list.stream()
                        .collect(Collectors.toMap(DeliveryNoteItemDO::getSourceId, DeliveryNoteItemDO::getDeliveryCount, BigDecimal::add));
            }
        }
        if (inDeliveryCountMap.size() > 0) {
            Map<Long, CountBean> countBeanMap = Maps.newHashMapWithExpectedSize(16);
            List<Object> sourceIds = new ArrayList<>(inDeliveryCountMap.keySet());
            List<CountBean> countBeanList = deliveryNoteItemDao.findCountBySource(sourceIds, ConstantForGYL.XSHT);
            if (org.apache.commons.collections.CollectionUtils.isNotEmpty(countBeanList)) {
                countBeanMap = countBeanList.stream().collect(Collectors.toMap(CountBean::getSourceId, v -> v));
            }
            //循环入参封装的map
            for (Long sourceId : inDeliveryCountMap.keySet()) {
                //根据合同id拿到每个销售合同数据
                SalescontractItemDO contractInfo = salescontractItemService.get(sourceId);
                BigDecimal contractCount =contractInfo.getCount() == null ? BigDecimal.ZERO:contractInfo.getCount();
                //查询该源单已被使用的总数量
                BigDecimal hadUseAllCount = BigDecimal.ZERO;
                CountBean countBean = countBeanMap.get(sourceId);
                if (countBean != null) {
                    hadUseAllCount = countBean.getMainCount();
                }
                //拿到当前数据该源单已被使用的总数量 //更新操作
                BigDecimal hadSaveCount = oldDeliveryCountMap.getOrDefault(sourceId,BigDecimal.ZERO);
                //得到数据库中其他使用该源单的条数，忽略自己使用
                BigDecimal otherUseContractCount = hadUseAllCount == null ? BigDecimal.ZERO : hadUseAllCount.subtract(hadSaveCount);
                //当前入参该源单数量总和 加上 数据库中已存在的源单数量总和 必须小于 合同上的数量 ,否则走报错
                if (contractCount.compareTo(inDeliveryCountMap.get(sourceId).add(otherUseContractCount)) < 0){
                    //取出传入数据中该源单的数据集
                    List<DeliveryNoteItemDO> sourceList = itemDos.stream()
                            .filter(itemDO -> Objects.equals(itemDO.getSourceId(),sourceId))
                            .collect(Collectors.toList());
                    //剩余发货数量
                    String hasCount = contractCount.subtract(otherUseContractCount).stripTrailingZeros().toPlainString();
                    //0 需要数量  1实际剩余数量 3合同单号
                    String [] args = {inDeliveryCountMap.get(sourceId).stripTrailingZeros().toPlainString(),hasCount,sourceList.get(0).getSourceCode()};
                    Map<String,Object> result = Maps.newHashMap();
                    result.put("sourceId",sourceId);
                    result.put("sourceCount",hasCount);
                    return R.error(500,messageSourceHandler.getMessage("stock.number.error", args),result);
                }
            }
        }
        return null;
    }

    @Override
    public R auditOrReverseAudit(Long id, Long auditSign) throws Exception {
        try {
            DeliveryNoteDO deliveryNote = deliveryNoteDao.findDeliveryNoteById(id);
            if (deliveryNote == null) {
                return R.error(messageSourceHandler.getMessage("common.massge.dateOfNon", null));

            }
            //不是相同的审核标志则更新，否则跳过
            if (!auditSign.equals(deliveryNote.getAuditSign())) {
                deliveryNoteDao.auditOrReverseAudit(id,auditSign, ShiroUtils.getUserId());
            }else {
                if (auditSign.equals(Constant.OK_AUDITED)) {
                    return R.error(messageSourceHandler.getMessage("common.massge.okAudit", null));
                } else {
                    return R.error(messageSourceHandler.getMessage("common.massge.okWaitAudit", null));
                }
            }
            return R.ok();
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage(),e);
            throw e;
        }
    }

    @Override
    public R findList(Map<String, Object> params) throws Exception {
        try {
            //返回结果
            Map<String, Object> result = Maps.newHashMapWithExpectedSize(3);
            //发货通知列表
            List<Map<String,Object>> list = deliveryNoteItemDao.findList(params);
            if (!CollectionUtils.isEmpty(list)) {
                //添加可执行数量
                List<Map<String, Object>> quoteLists = this.checkResourceCount(list,false);
                int count = deliveryNoteItemDao.findListCount(params);
                //数量金额合计
                Map<String, Object> sumMap = deliveryNoteItemDao.sumCountAndAmount(params);
                result.put("list",quoteLists);
                result.put("totalRows",count);
                result.put("totalSum",sumMap);
            }
            return R.ok(result);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage(),e);
            throw e;
        }
    }

    @Override
    public  List<Map<String,Object>> getDeliveryNoteList(Map<String, Object> params) throws Exception {
        try {
            //发货通知列表
            List<Map<String, Object>> list = deliveryNoteItemDao.findList(params);
            return CollectionUtils.isEmpty(list)?new ArrayList<>():list;
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage(),e);
            throw e;
        }

    }

    @Override
    public R getDetail(Long id) throws Exception {
        try {
            //返回结果
            Map<String, Object> result = Maps.newHashMapWithExpectedSize(2);
            Map<String, Object> headInfo = deliveryNoteItemDao.findHeadInfo(id);
            List<Map<String, Object>> bodyInfo = deliveryNoteItemDao.findBodyInfo(id);
            //添加可执行数量
            if (!CollectionUtils.isEmpty(bodyInfo)) {
                checkResourceCountForItem(bodyInfo);
            }
            result.put("headInfo",headInfo);
            result.put("bodyInfo",bodyInfo);
            result.put("uploadAttachment", contentAssocService.listByAssocId(id, ConstantForGYL.DELIVERY_NOTE_FILE));
            return R.ok(result);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage(),e);
            throw e;
        }
    }
        //TODO 金蝶
     //添加可执行数量
    public void checkResourceCountForItem(List<Map<String,Object>> bodyInfo){
        try {
            CountBean countBean;
            //循环外单独查询已用数量
            List<Object> sourceIds = bodyInfo.stream().map(e -> e.get("id")).collect(Collectors.toList());
            List<CountBean> countBeanList = stockOutItemService.getUseCountBySource(sourceIds, ConstantForGYL.FHTZ);
            Map<Long, CountBean> countBeanMap = Maps.newHashMapWithExpectedSize(16);
            if (org.apache.commons.collections.CollectionUtils.isNotEmpty(countBeanList)) {
                countBeanMap = countBeanList.stream().collect(Collectors.toMap(CountBean::getSourceId, v -> v));
            }
            for (Map<String, Object> data : bodyInfo) {
                //固定写死源单类型，后期新增时带出存入
                data.put("thisSourceId", data.get("id"));
                data.put("thisSourceType", ConstantForGYL.FHTZ);
                data.put("thisSourceTypeName", "发货通知");
                //主单位已使用数量
                BigDecimal mainUseCount = BigDecimal.ZERO;
                //辅助单位已使用数量
                BigDecimal subUseCount = BigDecimal.ZERO;
                countBean = countBeanMap.get(Long.parseLong(data.get("id").toString()));
                if (countBean != null) {
                    mainUseCount = countBean.getMainCount();
                    //此处为出库数量
                    subUseCount = countBean.getSubCountOther();
                }
                //主单位可执行数量
                BigDecimal count = MathUtils.getBigDecimalByZero(data.get("deliveryCount")).subtract(mainUseCount);
                //辅单位可执行数量
                BigDecimal subCount = MathUtils.getBigDecimalByZero(data.get("deliveryCountSupport")).subtract(subUseCount);
                if (count.compareTo(BigDecimal.ZERO) <= 0) {
                    data.put("quoteCount", 0);
                    data.put("subQuoteCount", 0);
                } else {
                    data.put("quoteCount", count);
                    data.put("subQuoteCount",subCount);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage(),e);
        }
    }

    @Override
    public DeliveryNoteItemDO getItemDetail(Long id) throws Exception {
        try {
            return deliveryNoteItemDao.findItemDetail(id);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage(),e);
            throw e;
        }
    }

    @Override
    public List<DeliveryNoteItemDO> findItemDetailByIds(List<Long> itemIds) {
        return deliveryNoteItemDao.findItemDetailByIds(itemIds);
    }

    @Override
    public R findDialog(Map<String, Object> params) throws Exception {
       try {
           //返回结果
           Map<String, Object> result = Maps.newHashMapWithExpectedSize(2);
           //发货通知单上的数据查询
           List<Map<String, Object>> list = deliveryNoteItemDao.findList(params);
           if (CollectionUtils.isEmpty(list)) {
               return R.ok();
           }
           //校验可执行数量
           List<Map<String, Object>> quoteLists = this.checkResourceCount2(list,true);
//           List<Map<String, Object>> quoteLists = this.checkResourceCount(list,true);
           if (!CollectionUtils.isEmpty(quoteLists)) {
               int page = Integer.parseInt(params.get("page").toString());
               int pageSize = Integer.parseInt(params.get("pageSize").toString());
               List<Map<String, Object>> quoteList = PageUtils.startPage(quoteLists, page, pageSize);
               result.put("data", new DsResultResponse(page, pageSize, quoteLists.size(), quoteList));
           }
           return R.ok(result);
       } catch (Exception e) {
           e.printStackTrace();
           LOGGER.error(e.getMessage(),e);
           throw e;
       }
    }
    public List<Map<String,Object>> checkResourceCount(List<Map<String,Object>> list ,Boolean sign  ){
        try {
        CountBean countBean;
        //循环外单独查询已用数量
        List<Object> sourceIds = list.stream().map(e -> e.get("id")).collect(Collectors.toList());
        List<CountBean> countBeanList = stockOutItemService.getUseCountBySource(sourceIds, ConstantForGYL.FHTZ);
        Map<Long, CountBean> countBeanMap = Maps.newHashMapWithExpectedSize(16);
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(countBeanList)) {
            countBeanMap = countBeanList.stream().collect(Collectors.toMap(CountBean::getSourceId, v -> v));
        }
        for (Map<String, Object> data : list) {
            //固定写死源单类型，后期新增时带出存入
            data.put("thisSourceId", data.get("id"));
            data.put("thisSourceType", ConstantForGYL.FHTZ);
            data.put("thisSourceTypeName", "发货通知");
            //主单位已使用数量
            BigDecimal mainUseCount = BigDecimal.ZERO;
            //辅助单位已使用数量
            BigDecimal subUseCount = BigDecimal.ZERO;
            countBean = countBeanMap.get(Long.parseLong(data.get("id").toString()));
            if (countBean != null) {
                mainUseCount = countBean.getMainCount();
                //此处为出库数量
                subUseCount = countBean.getSubCountOther();
            }
            //主单位可执行数量
            BigDecimal count = MathUtils.getBigDecimalByZero(data.get("deliveryCount")).subtract(mainUseCount);
            //辅单位可执行数量
            BigDecimal subCount = MathUtils.getBigDecimalByZero(data.get("deliveryCountSupport")).subtract(subUseCount);
            if (count.compareTo(BigDecimal.ZERO) <= 0) {
                data.put("quoteCount", 0);
                data.put("subQuoteCount", 0);
            } else {
                data.put("quoteCount", count);
                data.put("subQuoteCount",subCount);
            }
        }
        //过滤数据
            if(sign){
                List<Map<String, Object>> quoteLists = list
                        .stream()
                        .filter(stringObjectMap -> MathUtils.getBigDecimal(stringObjectMap.get("subQuoteCount")).compareTo(BigDecimal.ZERO)>0)
                        .collect(Collectors.toList());
                return quoteLists;
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage(),e);
            List<Map<String, Object>>  result = new ArrayList<>();
            return result;
        }
    }
    public List<Map<String,Object>> checkResourceCount2(List<Map<String,Object>> list ,Boolean sign  ){
        try {
        CountBean countBean;
        //循环外单独查询已用数量
        List<Object> sourceIds = list.stream().map(e -> e.get("id")).collect(Collectors.toList());
        List<CountBean> countBeanList = stockOutItemService.getUseCountBySource2(sourceIds, ConstantForGYL.FHTZ);
        Map<Long, CountBean> countBeanMap = Maps.newHashMapWithExpectedSize(16);
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(countBeanList)) {
            countBeanMap = countBeanList.stream().collect(Collectors.toMap(CountBean::getSourceId, v -> v));
        }
        for (Map<String, Object> data : list) {
            //固定写死源单类型，后期新增时带出存入
            data.put("thisSourceId", data.get("id"));
            data.put("thisSourceType", ConstantForGYL.FHTZ);
            data.put("thisSourceTypeName", "发货通知");
            //主单位已使用数量
            BigDecimal mainUseCount = BigDecimal.ZERO;
            //辅助单位已使用数量
            BigDecimal subUseCount = BigDecimal.ZERO;
            countBean = countBeanMap.get(Long.parseLong(data.get("id").toString()));
            if (countBean != null) {
                mainUseCount = countBean.getMainCount();
                //此处为出库数量
                subUseCount = countBean.getSubCountOther();
            }
            //主单位可执行数量
            BigDecimal count = MathUtils.getBigDecimalByZero(data.get("deliveryCount")).subtract(mainUseCount);
            //辅单位可执行数量
            BigDecimal subCount = MathUtils.getBigDecimalByZero(data.get("deliveryCountSupport")).subtract(subUseCount);
            if (count.compareTo(BigDecimal.ZERO) <= 0) {
                data.put("quoteCount", 0);
                data.put("subQuoteCount", 0);
            } else {
                data.put("quoteCount", count);
//                data.put("subQuoteCount",subCount);
            }
        }
        //过滤数据
            if(sign){
                List<Map<String, Object>> quoteLists = list
                        .stream()
                        .filter(stringObjectMap -> MathUtils.getBigDecimal(stringObjectMap.get("deliveryCount")).subtract(ObjectUtils.isEmpty(stringObjectMap.get("executableCount")) ? BigDecimal.ZERO : (BigDecimal)stringObjectMap.get("executableCount")).compareTo(BigDecimal.ZERO)>0)
                        .collect(Collectors.toList());
//                List<Map<String, Object>> quoteLists = list
//                        .stream()
//                        .filter(stringObjectMap -> MathUtils.getBigDecimal(stringObjectMap.get("subQuoteCount")).compareTo(BigDecimal.ZERO)>0)
//                        .collect(Collectors.toList());
                return quoteLists;
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage(),e);
            List<Map<String, Object>>  result = new ArrayList<>();
            return result;
        }
    }


    @Override
    public R batchDelete(List<Long> ids) throws Exception {
         try {
             List<Long> idList = deliveryNoteDao.findAuditDeliveryNoteByIds(ids);
             if (CollectionUtils.isEmpty(idList)) {
                 deliveryNoteDao.deleteByIds(ids);
                 deliveryNoteItemDao.deleteByMainIds(ids);
                 //根据id和类别删除附件
                 Long[] idArr = ids.toArray(new Long[0]);
                 contentAssocService.removeByAssocIdAndType(idArr, ConstantForGYL.DELIVERY_NOTE_FILE);
                 return R.ok();
             } else {
                 return R.error("选中数据中不能包含已审核的数据！");
             }

         } catch (Exception e) {
             e.printStackTrace();
             LOGGER.error(e.getMessage(),e);
             throw e;
         }
    }

    @Override
    public void retrographyExecutableCount(Map<Long, BigDecimal> countOfThis) {
        Set<Long> idsAll = countOfThis.keySet();
       List<Long> ids = new ArrayList(idsAll);
        List<DeliveryNoteItemDO> itemDetailByIds = this.findItemDetailByIds(ids);
        if (!CollectionUtils.isEmpty(itemDetailByIds)) {
            itemDetailByIds.stream().forEach(aa->{
                Long id = aa.getId();
                BigDecimal executableCount = aa.getExecutableCount()==null?BigDecimal.ZERO:aa.getExecutableCount();
                if(countOfThis.containsKey(id)){
                    BigDecimal thisCount = countOfThis.get(id);
                    aa.setExecutableCount(executableCount.add(thisCount));
                }
            });
            deliveryNoteItemDao.batchUpdate(itemDetailByIds);
        }
    }


}
